package com.csust.automaticteach.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.csust.automaticteach.manager.auth.annotation.SaSpaceCheckPermission;
import com.csust.automaticteach.common.BaseResponse;
import com.csust.automaticteach.common.DeleteRequest;
import com.csust.automaticteach.common.ResultUtils;
import com.csust.automaticteach.constant.SpaceUserPermissionConstant;
import com.csust.automaticteach.exception.BusinessException;
import com.csust.automaticteach.exception.ErrorCode;
import com.csust.automaticteach.exception.ThrowUtils;
import com.csust.automaticteach.manager.cos.CosManager;
import com.csust.automaticteach.mapper.ResourceMapper;
import com.csust.automaticteach.model.dto.resource.ResourceAddRequest;
import com.csust.automaticteach.model.dto.resource.ResourceAddWithUrlRequest;
import com.csust.automaticteach.model.dto.resource.ResourceQueryRequest;
import com.csust.automaticteach.model.dto.resource.ResourceUpdateRequest;
import com.csust.automaticteach.model.entity.Resource;
import com.csust.automaticteach.model.entity.Space;
import com.csust.automaticteach.model.entity.User;
import com.csust.automaticteach.model.vo.generateteach.UploadReturnVO;
import com.csust.automaticteach.model.vo.resource.AdminResourceVO;
import com.csust.automaticteach.model.vo.resource.ResourceVO;
import com.csust.automaticteach.model.vo.resource.StatisticResourceVO;
import com.csust.automaticteach.service.ResourceService;
import com.csust.automaticteach.service.SpaceService;
import com.csust.automaticteach.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import static com.csust.automaticteach.constant.FileConstant.FILE_CAN_NOT_BE_NULL;
import static com.csust.automaticteach.constant.FileConstant.FILE_FAIL_DELETE;

/**
 * @ClassNameResourceController
 * @Description 资源控制器
 * @Author钰玟
 * @Date2025/7/16 下午10:20
 * @Version 1.0
 **/
@RestController
@RequestMapping("/resource")
@Slf4j
public class ResourceController {
    @jakarta.annotation.Resource
    private ResourceService resourceService;
    @jakarta.annotation.Resource
    private ResourceMapper resourceMapper;
    @jakarta.annotation.Resource
    private UserService userService;
    @jakarta.annotation.Resource
    private SpaceService spaceService;
    @jakarta.annotation.Resource
    private CosManager cosManager;
    @jakarta.annotation.Resource
    private TransactionTemplate transactionTemplate;

    @PostMapping("/upload")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_UPLOAD)
    public BaseResponse<UploadReturnVO> uploadResourceFile(@RequestParam("file") MultipartFile file,@RequestParam(required = false) Long spaceId, HttpServletRequest request) throws IOException {
        // 校验文件
        ThrowUtils.throwIf(file.isEmpty(), ErrorCode.PARAMS_ERROR, FILE_CAN_NOT_BE_NULL);
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);
        UploadReturnVO uploadReturnVO = resourceService.uploadResourceFile(file,spaceId, loginUser);
        return ResultUtils.success(uploadReturnVO);
    }

    @PostMapping("/add")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_EDIT)
    public BaseResponse<Boolean> addResource(@RequestBody ResourceAddRequest resourceAddRequest,HttpServletRequest request) {
        // 校验文件
        ThrowUtils.throwIf(resourceAddRequest == null, ErrorCode.PARAMS_ERROR);
        com.csust.automaticteach.model.entity.Resource resource = new com.csust.automaticteach.model.entity.Resource();
        //校验用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        // 校验空间是否存在
        Long spaceId = resourceAddRequest.getSpaceId();
        if (spaceId != null) {
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 必须空间创建人（管理员）才能上传
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            }
        }
        BeanUtil.copyProperties(resourceAddRequest, resource);
        boolean result = resourceService.saveOrUpdate(resource);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    @PostMapping("/add/url")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_UPLOAD)
    public BaseResponse<Boolean> addResourceWithUrl(@RequestBody ResourceAddWithUrlRequest resourceAddWithUrlRequest,HttpServletRequest request) {
        // 校验文件
        ThrowUtils.throwIf(resourceAddWithUrlRequest == null, ErrorCode.PARAMS_ERROR);
        Resource resource = new Resource();
        //校验用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        // 校验空间是否存在
        Long spaceId = resourceAddWithUrlRequest.getSpaceId();
        if (spaceId != null) {
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 必须空间创建人（管理员）才能上传
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            }
        }
        BeanUtil.copyProperties(resourceAddWithUrlRequest, resource);
        boolean result = resourceService.saveOrUpdate(resource);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }


    /**
     * 获取列表（封装类）
     * @param resourceQueryRequest 查询参数
     * @param request 请求
     * @return
     */
    @PostMapping("/list/page/vo")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_VIEW)
    public BaseResponse<Page<ResourceVO>> listResourceVOByPage(@RequestBody ResourceQueryRequest resourceQueryRequest
            , HttpServletRequest request) {
        ThrowUtils.throwIf(resourceQueryRequest == null, ErrorCode.PARAMS_ERROR);
        long current = resourceQueryRequest.getCurrent();
        long pageSize = resourceQueryRequest.getPageSize();
        User loginUser = userService.getLoginUser(request);
        resourceQueryRequest.setUserId(loginUser.getId());
        // 空间权限校验
        Long spaceId = resourceQueryRequest.getSpaceId();
        // 公开资源库
        if (spaceId == null) {
            // 普通用户默认只能查看已过审的公开数据
            resourceQueryRequest.setNullSpaceId(true);
        } else {
            // 私有空间
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            }
        }
        Page<Resource> resourcePage = resourceService.page(new Page<>(current, pageSize),
                resourceService.getResourceQueryWrapper(resourceQueryRequest));
        Page<ResourceVO> resourceVOPage = new Page<>(current, pageSize, resourcePage.getTotal());
        resourceVOPage.setRecords(resourceService.getResourceVOList(resourcePage.getRecords()));
        return ResultUtils.success(resourceVOPage);
    }
    /**
     * 获取资源列表
     * @param resourceQueryRequest 查询参数
     * @param request 请求
     * @return
     */
    @PostMapping("/list/page")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_VIEW)
    public BaseResponse<Page<AdminResourceVO>> listResourceByPage(@RequestBody ResourceQueryRequest resourceQueryRequest
            , HttpServletRequest request) {
        ThrowUtils.throwIf(resourceQueryRequest == null, ErrorCode.PARAMS_ERROR);
        long current = resourceQueryRequest.getCurrent();
        long pageSize = resourceQueryRequest.getPageSize();
        Page<Resource> resourcePage = resourceService.page(new Page<>(current, pageSize),
                resourceService.getResourceQueryWrapper(resourceQueryRequest));
        Page<AdminResourceVO> adminResourceVOPage = new Page<>(current, pageSize, resourcePage.getTotal());
        adminResourceVOPage.setRecords(resourceService.getAdminResourceVOList(resourcePage.getRecords()));
        return ResultUtils.success(adminResourceVOPage);
    }

    /**
     * 获取资源列表
     * @param resourceUpdateRequest 更新参数
     * @param request 请求
     * @return
     */
    @PostMapping("/update")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_EDIT)
    public BaseResponse<Boolean> updateResource(@RequestBody ResourceUpdateRequest resourceUpdateRequest
            , HttpServletRequest request) {
        ThrowUtils.throwIf(resourceUpdateRequest == null, ErrorCode.PARAMS_ERROR);
        //校验用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        //校验空间id相关逻辑
        Long resourceId = resourceUpdateRequest.getId();
        Long spaceId = resourceUpdateRequest.getSpaceId();
        if (resourceId != null) {
            Resource oldResource = resourceService.getById(resourceId);
            ThrowUtils.throwIf(oldResource == null, ErrorCode.NOT_FOUND_ERROR, "资源不存在");
            // 仅本人或管理员可编辑
            if (!oldResource.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
            }
            // 校验空间是否一致
            // 没传 spaceId，则复用原有图片的 spaceId
            if (spaceId == null) {
                if (oldResource.getSpaceId() != null) {
                    spaceId = oldResource.getSpaceId();
                }
            } else {
                // 传了 spaceId，必须和原有图片一致
                if (ObjUtil.notEqual(spaceId, oldResource.getSpaceId())) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间 id 不一致");
                }
            }
        }
        Resource resource = new Resource();
        BeanUtil.copyProperties(resourceUpdateRequest, resource);
        boolean b = resourceService.updateById(resource);
        ThrowUtils.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }


    /**
     * 删除
     * @param deleteRequest deleteRequest
     * @return BaseResponse<Boolean>
     */
    @PostMapping("/delete")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_DELETE)
    public BaseResponse<Boolean> deleteResource(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        Long id = deleteRequest.getId();
        ThrowUtils.throwIf(id <= 0 , ErrorCode.PARAMS_ERROR);
        //从数据库中获取key (先获取url地址再截取key)
        boolean deleted = resourceService.deleteById(id, request);
        ThrowUtils.throwIf(!deleted, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }
    /**
     * 批量删除
     * @param idList 删除id列表
     * @return BaseResponse<Boolean>
     */
    @PostMapping("/delete/batch")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_DELETE)
    public BaseResponse<Boolean> deleteResourceWithBatch(@RequestBody List<Long> idList) {
        ThrowUtils.throwIf(CollUtil.isEmpty(idList), ErrorCode.PARAMS_ERROR);

        //从数据库中获取key (先获取url地址再截取key)
        List<Resource> resourceList = resourceMapper.selectByIds(idList);
        List<String> keyList = resourceList.stream()
                .map(Resource::getFileUrl)
                .map(fileUrl -> fileUrl.substring(fileUrl.lastIndexOf("//") + 1))
                .toList();
        try {
            for (String key : keyList) {
                cosManager.deleteFile(key);
            }
        } catch (Exception e) {
            log.error("fail to delete the file,the reason is:{}", e.getMessage());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, FILE_FAIL_DELETE);
        }
        boolean result = resourceService.removeBatchByIds(idList);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }


    @PostMapping("/statistic/total")
    @SaSpaceCheckPermission(SpaceUserPermissionConstant.RESOURCE_VIEW)
    public BaseResponse<StatisticResourceVO> getTotalResourceCount(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();
        QueryWrapper<Resource> queryWrapper = new QueryWrapper<Resource>().eq("userId", userId);
        long totalCount = resourceService.count(queryWrapper);
        long categoryTotalCount = resourceMapper.countDistinct("category");

        List<String> categoryList = resourceMapper.selectObjs(
                        new QueryWrapper<Resource>()
                                .select("DISTINCT category")   // 去重
                ).stream()
                .map(Object::toString) // Object → String
                .toList();

        StatisticResourceVO statisticResourceVO = new StatisticResourceVO();
        statisticResourceVO.setCategoryList(categoryList);
        statisticResourceVO.setTotalResourceCount(totalCount);
        statisticResourceVO.setTotalCategoryCount(categoryTotalCount);
        return ResultUtils.success(statisticResourceVO);
    }

}
